/*****************************************************************

The GUI code is based on Run applet Copyright (c) 2000 Matthias Elter <elter@kde.org>

Modifications by Sergejs Melderis, 2006 <sergey.melderis@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

******************************************************************/



#include <kurl.h>
#include <kio/job.h>        
#include <qdir.h>
#include <qtextstream.h>        
#include <ktempdir.h>        
#include <kstandarddirs.h>
#include <kaboutdata.h>
#include <kaboutapplication.h>
#include <kglobal.h>
#include <klocale.h>
#include <kconfig.h>
#include <kapplication.h>
#include <kmessagebox.h>
#include <khtml_part.h>
#include <kurl.h>
#include <kparts/browserextension.h>
#include <kcombobox.h>
#include <khtmlview.h>
#include <qpopupmenu.h>
#include <stdlib.h>
#include <kconfigdialog.h>
#include <qregexp.h>
#include <qlayout.h>
#include <qpixmap.h>
#include <qmime.h>
#include <qimage.h>
#include <qpushbutton.h>
#include <qfont.h>
#include <qhbox.h>
#include <qtooltip.h>
#include <qdeepcopy.h>
#include <qfile.h>
#include "klingvotranslator.h"
#include "textencoder.h"
#include "browser.h"
#include "languagechooser.h"
#include "prefs.h"
#include "settings.h"
#include "browser_prefs.h"
#include "browserpopupmenu.h"
#include "wordquizwriter.h"
#include "wordquizfilechooser.h"
#include "filesprefs.h"
#include <kwin.h>

        // debug
#include <qapplication.h>

#include <qtextcodec.h>

// maximum of specified a und b
#define MAX(a,b) (((a)>(b)) ? (a) : (b))


KLingvoTranslator::KLingvoTranslator(const QString& configFile, Type type, int actions, QWidget *parent, const char *name)
    : KPanelApplet(configFile, type, actions, parent, name),mBrowser(0), mEncoder(0), mTempDir(0)
{
    DCOPObject::setObjId("KLingvoTranslator");
    char * en_xpm[] = {
        "17 16 3 1",
        " 	c None",
        ".	c #004188",
        "+	c #FFFFFF",
        ".................",
        ".................",
        ".................",
        ".................",
        ".................",
        "...+++++.+....+..",
        "...+.....++...+..",
        "...+.....+.+..+..",
        "...++++..+..+.+..",
        "...+.....+...++..",
        "...+.....+....+..",
        "...+++++.+....+..",
        ".................",
        ".................",
        ".................",
        "................."};


    char * ge_xpm[] = {
        "17 16 3 1",
        " 	c None",
        ".	c #004188",
        "+	c #FFFFFF",
        ".................",
        ".................",
        ".................",
        ".................",
        ".................",
        ".....+++..+++++..",
        "....+...+.+......",
        "...+......+......",
        "...+..+++.++++...",
        "...+....+.+......",
        "....+...+.+......",
        ".....++++.+++++..",
        ".................",
        ".................",
        ".................",
        "................."};

     char * it_xpm[] = {
        "17 16 3 1",
        " 	c None",
        ".	c #004188",
        "+	c #FFFFFF",
        ".................",
        ".................",
        ".................",
        ".................",
        ".................",
        "...+++.+++++.....",
        "....+....+.......",
        "....+....+.......",
        "....+....+.......",
        "....+....+.......",
        "....+....+.......",
        "...+++...+.......",
        ".................",
        ".................",
        ".................",
        "................."};

     char * ru_xpm[] = {
        "17 16 3 1",
        " 	c None",
        ".	c #004188",
        "+	c #FFFFFF",
        ".................",
        ".................",
        ".................",
        ".................",
        ".................",
        "...++++..+....+..",
        "...+...+.+....+..",
        "...+...+.+....+..",
        "...++++..+....+..",
        "...+.+...+....+..",
        "...+..+..+....+..",
        "...+...+..++++...",
        ".................",
        ".................",
        ".................",
        "................."};

     char * sp_xpm[] = {
        "17 16 3 1",
        " 	c None",
        ".	c #004188",
        "+	c #FFFFFF",
        ".................",
        ".................",
        ".................",
        ".................",
        ".................",
        "....++++.++++....",
        "...+.....+...+...",
        "...+.....+...+...",
        "....+++..+...+...",
        ".......+.++++....",
        ".......+.+.......",
        "...++++..+.......",
        ".................",
        ".................",
        ".................",
        "................."};

    char * fr_xpm[] = {
        "17 16 3 1",
        " 	c None",
        ".	c #004188",
        "+	c #FFFFFF",
        ".................",
        ".................",
        ".................",
        ".................",
        ".................",
        "...+++++.++++....",
        "...+.....+...+...",
        "...+.....+...+...",
        "...++++..++++....",
        "...+.....+.+.....",
        "...+.....+..+....",
        "...+.....+...+...",
        ".................",
        ".................",
        ".................",
        "................."};

    // statical icon for browser window converted from
    // http://www.lingvo.ru/upload/images/Lingvo_16x16.ico
    static char * icon_xpm[] = {
      /* columns rows colors chars-per-pixel */
      "16 16 83 1",
      "  c #702705",
      ". c #752D07",
      "X c #742D0B",
      "o c #793104",
      "O c #813A0E",
      "+ c #8C4701",
      "@ c #954D08",
      "# c #904B0F",
      "$ c #96510D",
      "% c #99550E",
      "& c #934D15",
      "* c #995416",
      "= c #9C5913",
      "- c #9F5C10",
      "; c #9B5D19",
      ": c #A25E11",
      "> c #A25E19",
      ", c #AE6B09",
      "< c #B26E0A",
      "1 c #B4700D",
      "2 c #B9760E",
      "3 c #A3601A",
      "4 c #B26E18",
      "5 c #B16E1E",
      "6 c #A35D3B",
      "7 c #AC683D",
      "8 c #C17F22",
      "9 c #AA6541",
      "0 c #AE6943",
      "q c #AE694A",
      "w c #B16C46",
      "e c #BF800B",
      "r c #C4870B",
      "t c #CD8F0E",
      "y c #C68611",
      "u c #CC8B13",
      "i c #C28718",
      "p c #CF9217",
      "a c #D19314",
      "s c #D79915",
      "d c #D7921E",
      "f c #DFA418",
      "g c #DDA51D",
      "h c #E0A418",
      "j c #C4822A",
      "k c #D29420",
      "l c #CC9538",
      "z c #DDA226",
      "x c #E4A127",
      "c c #E3A628",
      "v c #ECA82D",
      "b c #F8AF37",
      "n c #F3A43E",
      "m c #F8AF38",
      "M c #F6B230",
      "N c #F8B432",
      "B c #F8B136",
      "V c #F4B039",
      "C c #CD8D50",
      "Z c #D0915C",
      "A c #DCBC57",
      "S c #F7A545",
      "D c #F9A645",
      "F c #F9A449",
      "G c #E3A45E",
      "H c #E5BE5F",
      "J c #DB9E62",
      "K c #DFA363",
      "L c #E2A564",
      "P c #EAAB60",
      "I c #E2C664",
      "U c #E4C96C",
      "Y c #E9C777",
      "T c #F3DA9A",
      "R c #DCC8AD",
      "E c #F3DFA7",
      "W c #F6E1A8",
      "Q c #F0E1AD",
      "! c #FAE8B9",
      "~ c #F7EACA",
      "^ c #FBEFD0",
      "/ c #FEFBF3",
      "( c None",
      /* pixels */
      "RAIUUUUUUUUUUQ((",
      "OiYW!!!!!!!!!^/(",
      ".@yHTTTTTTTTTTE~",
      " o1affgfgfgfgggz",
      "&#2tfMMMMMMMMMMS",
      "9wjkcVNNNNNNNNNF",
      "&0ZJKGVNNNNNNNBF",
      ".#%-:4vNNNNNNNMF",
      "X+<rsvMNNNNNNNNF",
      "6$2tfMNNNNNNNNBF",
      "q78pxMNNNNNNNNNF",
      "#*CKLPVNNNNNNNmD",
      "o+=3>5vNNNNNNNNF",
      "X+,eaxMNNNNNNNbF",
      "(;2thMNNNNNNNNmD",
      "((lyudnDDDDDDDDF"
    };

    QMimeSourceFactory::defaultFactory()->setImage( "English", QImage(en_xpm) );
    QMimeSourceFactory::defaultFactory()->setImage( "French",  QImage(fr_xpm) );
    QMimeSourceFactory::defaultFactory()->setImage( "German",  QImage(ge_xpm) );
    QMimeSourceFactory::defaultFactory()->setImage( "Italian", QImage(it_xpm) );
    QMimeSourceFactory::defaultFactory()->setImage( "Spanish", QImage(sp_xpm) );
    QMimeSourceFactory::defaultFactory()->setImage( "Russian", QImage(ru_xpm) );
    // browser window icon is available under the name "Icon" (see browser.cpp)
    QMimeSourceFactory::defaultFactory()->setImage( "Icon", QImage(icon_xpm) );

    setBackgroundOrigin( AncestorOrigin );
    setenv("HISTCONTROL", "ignoredups", 1);


    mFromLanguage = Prefs::fromLanguage();
    mToLanguage = Prefs::toLanguage();
    setTranslitMode();
    mPatternForCompletion = Prefs::regExpForCompletion();
    mLanguageList = Prefs::languagesList();

    mChooser = new LanguageChooser(mFromLanguage, mToLanguage, this);
    mChooser->setBackgroundOrigin(AncestorOrigin);
    mChooser->setFixedHeight(18);
    connect(mChooser, SIGNAL(languageChange(const QString &, const QString &)),
            this, SLOT(changeLanguages(const QString &, const QString &)));
    connect(mChooser, SIGNAL(translateClipboard(const QString &)),
            this, SLOT(translateClipboard(const QString &)));

    KIconLoader *iconLoader = KGlobal::iconLoader();

    // button to clear input field
    pmClearInput = new QPixmap();
    *pmClearInput = iconLoader->loadIcon("locationbar_erase.png", KIcon::NoGroup, KIcon::SizeSmall);
    mClearInputB = new FlatButton(this, pmClearInput);
    mClearInputB->setBackgroundOrigin(AncestorOrigin);
    mClearInputB->setFixedSize(16, 16);
    connect(mClearInputB, SIGNAL(pressed()), this, SLOT(clearInput()));


    mInput = new KHistoryCombo(this);
    mInput->setFocus();
    mInput->setEditable(true);
    mInput->setInsertionPolicy(QComboBox::NoInsertion);
    
    KConfig *c = config();
    KCompletion *comp = mInput->completionObject();
    c->setGroup("Completion");
    QStringList l = c->readListEntry(mFromLanguage + " Completion List");
    comp->setItems(l);
    l = c->readListEntry(mFromLanguage + " History List");
    mInput->setHistoryItems(l);
    mInput->clearEdit();
    connect(mInput, SIGNAL(activated( const QString&)),
            this, SLOT(translate( const QString& )));
    connect(mInput, SIGNAL(textChanged(const QString&)),
            this, SLOT(textChanged(const QString&)));
    mPath = Prefs::pathToLingvoTranslate();
    mUrl = Prefs::urlToLingvo();
    mUrl.setPath(mPath);


    // setup popup button
    mBtn = new QPushButton(i18n("Trans"), this);
    QFont f = mBtn->font();
    f.setPixelSize(12);
    mBtn->setFont(f);
    QToolTip::add(mBtn, i18n("Translate with Lingvo Online"));
    connect(mBtn, SIGNAL(clicked()), SLOT(popupCombo()));

    mContextMenu = new QPopupMenu(this);
    mContextMenu->insertItem("Translate From", mChooser->getFromMenu());
    mContextMenu->insertItem("Translate To", mChooser->getToMenu());
    setCustomMenu(mContextMenu);
    watchForFocus(mInput->lineEdit());
    mEncoder = new TextEncoder();

    mHbox = new QHBox( 0, 0, WStyle_Customize | WType_Popup );
    mHbox->setFixedSize(120, 22);
    QToolTip::add(this, i18n("Translate with Lingvo Online"));
    FilesPrefs::self().setConfig(config());
    if (Prefs::firstRun()) {
        reconfigure();
    }
    
}




KLingvoTranslator::~KLingvoTranslator()
{
    KConfig *c = config();
    Prefs::setFromLanguage(mFromLanguage);
    Prefs::setToLanguage(mToLanguage);
    Prefs::setFirstRun(false);
    Prefs::writeConfig();
    c->setGroup("Completion");
    c->writeEntry(mFromLanguage + " Completion List", mInput->completionObject()->items());
    c->writeEntry(mFromLanguage + " History List", mInput->historyItems());
    c->sync();
    delete mEncoder;
    delete mBrowser;
    delete mHbox;
    delete pmClearInput;
    if (mTempDir)
        delete mTempDir;

}


void KLingvoTranslator::about()
{
    KAboutData about("klingvoonline", I18N_NOOP("KLingvoOnline"), "0.2",
                     I18N_NOOP("Lingvo Online launcher"),
                     KAboutData::License_GPL_V2,
                     "(C) 2006 Sergejs Melderis");
    about.addAuthor("Sergejs Melderis", 0, "sergey.melderis@gmail.com");
    about.setBugAddress("sergey.melderis@gmail.com");
    KAboutApplication a(&about, this);
    a.exec();
}


void KLingvoTranslator::help()
{
    KMessageBox::information(0, i18n("This is a help box"));
}

void KLingvoTranslator::preferences()
{
    preferences(Fonts); 
}

void KLingvoTranslator::preferences(int activePage)
{
    
    if (KConfigDialog::showDialog("settings"))
        return;
    KConfigDialog *dialog = new KConfigDialog(this,
       "settings", Prefs::self(), KDialogBase::IconList, KDialogBase::Default|KDialogBase::Ok|
               KDialogBase::Apply|KDialogBase::Cancel);
    dialog->setCaption(i18n("Configure - KLingvoOnline"));
    SettingsWidget *confWdg =  new SettingsWidget( 0, "Transliteration" );
    dialog->addPage(confWdg,  i18n("Transliteration"), "key_bindings");
    FontSettingsWidget *fontConfWdg = new FontSettingsWidget(0, "Font Settings");
    dialog->addPage(fontConfWdg, i18n("Fonts"), "fonts");

    WordQuizFileChooser *chooser = new WordQuizFileChooser(0, "KWordQuiz Files");
    dialog->addPage(chooser, i18n("KWordQuiz Files"), "kwordquiz");

    connect(chooser, SIGNAL(selectionChanged(bool)), dialog, SLOT(enableButtonApply(bool)));
    connect(dialog,  SIGNAL(applyClicked()), this, SLOT(reconfigure()));
    connect(dialog, SIGNAL(okClicked()), this, SLOT(reconfigure()));
    dialog->showPage(activePage);
    dialog->show();
}

void KLingvoTranslator::reconfigure()
{
    FilesPrefs::self().writeConfig();
    transliterate = Prefs::transliterateMode();

    //It is sort of a hack.
    //Apparently KHTMLPart will use kicker config, because this is not a standalone application.
    KConfig c("kickerrc", false, false);
    c.setGroup("HTML Settings");
    c.writeEntry("MinimumFontSize", Prefs::minimumFontSize());
    c.writeEntry("MediumFontSize", Prefs::mediumFontSize());

    //We will use konqueror fonts for the browser.
    KConfig konqConfig("konquerorrc");
    konqConfig.setGroup("HTML Settings"); 
    QString fonts = konqConfig.readEntry("Fonts");

    c.writeEntry("Fonts", fonts);
    c.sync();
    KGlobal::config()->reparseConfiguration();
    if (mBrowser) {
        mBrowserMenu->reconfigure();
        mWordWriter->reconfigure();

        //If browser is shown schedule instantiation of a new browser with new configuration.
        if (mBrowser->isShown())
            connect(mBrowser, SIGNAL(closed()), this, SLOT(deleteBrowser()));
    }
}

void KLingvoTranslator::setUpKWordQuizFiles()
{
    preferences(KWordQuizFiles);
}

int KLingvoTranslator::widthForHeight(int /* height */) const
{
    // maximum of mChooser and mInput
    return MAX(mChooser->sizeHint().width(), 125);
}

int KLingvoTranslator::heightForWidth(int /* width */) const
{
    return 22;
}

void KLingvoTranslator::resizeEvent(QResizeEvent  * /* e */)
{
    if(orientation() == Horizontal)
    {
        mBtn->hide();
        // positioning of button relative to other widgets
        // suppose, that the button dimensions are 16x16
        mClearInputB->reparent(this, QPoint(0,0), true);
        mInput->reparent(this, QPoint(0,16), true);
        mChooser->setGeometry(0,0, width(), mChooser->height());

        if(height() >= mInput->sizeHint().height() + mChooser->height())
        {
            int inputVOffset = height() - mInput->sizeHint().height() - 2;
            int labelHeight = mChooser->sizeHint().height();
            mChooser->setGeometry(0, inputVOffset - labelHeight,
                                width(), labelHeight);
            mClearInputB->setGeometry(0, inputVOffset + (mInput->sizeHint().height()-16) / 2,
                                16, mInput->sizeHint().height());
            mInput->setGeometry(16, inputVOffset,
                                width()-16, mInput->sizeHint().height());
            mChooser->show();
        }
        else
        {
            mChooser->hide();

                    // make it as high as the combobox naturally wants to be
                    // but no taller than the panel is!
                    // don't forget to center it vertically either.
            int newHeight = mInput->sizeHint().height();
            if (newHeight > height())
                newHeight = height();
            mInput->setGeometry(0, (height() - newHeight) / 2,
                                width(), newHeight);
        }
    }
    else
    {
        mClearInputB->hide();
        mBtn->show();
        mBtn->setFixedSize(width(), 22);
        mInput->reparent( mHbox, QPoint(0, 0), false);
        mChooser->hide();
    }
}


extern "C"
{
    KPanelApplet* init( QWidget *parent, const QString& configFile)
    {
        KGlobal::locale()->insertCatalogue("klingvoonline");
        return new KLingvoTranslator(configFile, KPanelApplet::Stretch,
                             KPanelApplet::About  | KPanelApplet::Preferences,
                             parent, "klingvoonline");
    }
}

void KLingvoTranslator::clearInput()
{
    mInput->setActiveWindow ();
    mInput->setFocus();
    mInput->clearEdit();
}

void KLingvoTranslator::translateWordDCOP(const QString &word)
{
  translateClipboard(word);
}

void KLingvoTranslator::translateClipboard()
{
  mChooser->translateClipboard();
}

void KLingvoTranslator::translateClipboard(const QString &word)
{
    disconnect(mInput, SIGNAL(textChanged(const QString&)),
               this, SLOT(textChanged(const QString&)));
    mInput->setEditText(word);
    // call event handler explicitly to change text in mInput
    // (important for following call to translate())
    textChanged (word);
    connect(mInput, SIGNAL(textChanged(const QString&)),
            this, SLOT(textChanged(const QString&)));
    translate(word);
}

void KLingvoTranslator::translate( const QString &word)
{
    mCurWord = word; // we'll need it later for parsing in mayBeAddWordToCompletion()
    if (word.length() == 0)
        return;
    QString query;
    QString languageIndexStr = QString::number(languageIndex(word));

    // It's not necessary make check of current language at this place
    // See exlanation in function TextEncoder::encodeForLingvo
    query = "?words=" + mEncoder->encodeForLingvo(word) +
            "&ln=" + languageIndexStr;

    if (!mBrowser) {
        instantiateBrowser();
    }
    mBrowser->setCaption("KLingvoTranslator - " + word);
    if (!Prefs::hasSeenIntro()) {
        mUrl.setQuery(query);
        mBrowser->resize(800, 800);
        this->showFirstTimeHelp();
    }
    else
        mBrowser->openPageForQuery(query);
    mBrowser->show();
    mBrowser->raise();
    KWin::activateWindow(mBrowser->winId());
}

void KLingvoTranslator::instantiateBrowser() {
    mBrowserMenu = new BrowserPopupMenu(this);
    mBrowserMenu->reconfigure();
    if (mBrowser) {
        return;
    }
    mBrowser = new Browser(0,  mBrowserMenu);

    mBrowser->setURL(mUrl);

    mWordWriter = new WordQuizWriter(this);
    mWordWriter->reconfigure();
    connect(mBrowser->htmlPart(), SIGNAL(completed()),
            this, SLOT(mayBeAddWordToCompletion()));

    connect(mBrowserMenu, SIGNAL (translateActivated(const QString &)),
            this, SLOT(translate(const QString &)));

    connect(mBrowserMenu, SIGNAL(addToFileActivated(const QString &, const QString &, const QString &)),
            mWordWriter, SLOT(addWord(const QString &, const QString &, const QString &)));

    connect(mBrowserMenu, SIGNAL(requestAddWordQuizFiles()), SLOT(setUpKWordQuizFiles()));
    
    connect(mWordWriter, SIGNAL(addWordCompleted(const QString &)),
            mBrowser, SLOT(showAddWordResult(const QString&)));  
}


void KLingvoTranslator::setTranslitMode()
{
    transliterate = Prefs::transliterateMode();
}

QString KLingvoTranslator::checkInput(const QString &w)
{
    // This is silly of course. We just look at the first
    // character to see if it is Russian or not.
    QString input;
    QChar first = w.at(0);
    if( (first >= QChar(0x0410) && first <= QChar(0x044F) )
       ||first == QChar(0x0451) ||  first == QChar(0x0401) ) {
        input =  "Russian";
    } else {
        // alternate language is not always "English"
        input = mFromLanguage == "Russian" ? mToLanguage : mFromLanguage;
    }    return input;
}

void KLingvoTranslator::transliterateText(const QString &t)
{
    // first make all letters latin, then transliterate to russian
    QString text = mEncoder->englishToRussian(mEncoder->russianToEnglish(t));
    disconnect(mInput, SIGNAL(textChanged(const QString&)),
               this, SLOT(textChanged(const QString&)));
    mInput->setEditText(text);
    connect(mInput, SIGNAL(textChanged(const QString&)),
            this, SLOT(textChanged(const QString&)));
}


void KLingvoTranslator::mayBeAddWordToCompletion()
{
    if (!mBrowser)
        return;
    QString doc = mBrowser->htmlPart()->documentSource();
    QRegExp reg(mPatternForCompletion);
    // mPatternForCompletion should have a pattern that will match
    // only if the word is  found.
    if (reg.search(doc) != -1) {
        // Find the actual phrase.
        QString capture = reg.cap(1);

        // For not English characters Lingvo uses decimal representation. Ex &#1087;
        // We need to translate it to unicode. But there are also could be spaces...
        QValueList<int> spaces;
        int i = 0;
        while ( (i = capture.find(' ', i)) != -1 ) {
            spaces.append(i / 7);
            i++;
        }

        QRegExp splitRegExp(";&#|&#|;");
        QStringList list = QStringList::split(splitRegExp, capture);

        QString result;
        for (QStringList::Iterator it = list.begin(); it != list.end(); ++it) {
            QString s = *it;
            int i = s.find(';');
            if( i != -1 )
               s.truncate(i);
            // Let's try to convert it to a number. If it is not a number it is a string, so append the string.
            bool ok;
            unsigned short chCode = s.toUShort(&ok);
            QChar ch(chCode);
            if (ok)
                result.append(ch);
            else
                result.append(s);

            // It could be a place where we need to append  a space.
            if (!spaces.isEmpty()) {
                int pos = spaces.first();
                if (pos == result.length()) {
                    result.append(' ');
                    spaces.pop_front();
                }
            }
        }

        // If it is sort of the same phrase as user typed in, add it to completion.
        if (mCurWord.startsWith(result) || result.startsWith(mCurWord)) {
            mInput->addToHistory(result);
            QStringList l = mInput->historyItems();
            l.sort();
            mInput->setHistoryItems(l);
        }
        mCurWord = result;
        mBrowserMenu->setCurrentWord(mCurWord);
    } else {
        mBrowserMenu->setCurrentWord(QString::null);
    }
}

void KLingvoTranslator::textChanged(const QString &text)
{
    if (text.length() == 0)
        return;
    if (transliterate && mFromLanguage == "Russian")
        transliterateText(text);
    QString inputLanguage = checkInput(mInput->currentText());


    // If a user types Russian characters but the current language is
    // not Russian we activate  menu item that corresponds to Russian.
    // That will cause change the current language to Russian
    if (inputLanguage == "Russian" && mFromLanguage != "Russian") {
        // Switch target language to source (is not always "English")
        mToLanguage = mFromLanguage;
        // set Russian as current for translation
        mFromLanguage = "Russian";
        // It's enought to change only target language,
        // source will be changed to "Russian" automaticly
        mChooser->getToMenu()->activateItemAt(mLanguageList.findIndex(mToLanguage));
    }
    // if a user types not Russian characters but the current language is Russian
    // Russian we activate menu item that corresponds to English.
    // TODO It would be better if we could get the current keyboard layout
    // instead of checkInput(). See checkInput() what it does.
    else if (inputLanguage != "Russian" && mFromLanguage == "Russian") {
        // Change source language to target language
        mFromLanguage = mToLanguage;
        mToLanguage = "Russian";
        // It's enought to change only source language,
        // target will be changed to "Russian" automaticly
        mChooser->getFromMenu()->activateItemAt(mLanguageList.findIndex(mFromLanguage));
    }
}

void KLingvoTranslator::mousePressEvent(QMouseEvent *e)
{
    if ( e->button() != RightButton ) {
        KPanelApplet::mousePressEvent( e );
        return;
    }
    mContextMenu->exec(e->globalPos());
}

void KLingvoTranslator::changeLanguages(const QString &newFrom, const QString &newTo)
{
    KCompletion *comp = mInput->completionObject();
    if (newFrom != mFromLanguage) {
        QString currentInputText = mInput->currentText();
        // TODO  check if it is needed
        disconnect(mInput, SIGNAL(textChanged(const QString&)),
                   this, SLOT(textChanged(const QString&)));
        KConfig *c = config();
        c->setGroup("Completion");
        c->writeEntry(mFromLanguage + " Completion List", comp->items());
        c->writeEntry(mFromLanguage + " History List", mInput->historyItems());
        c->sync();
        QStringList list = c->readListEntry(newFrom + " Completion List");
        comp->setItems(list);
        list = c->readListEntry(newFrom + " History List");
        mInput->setHistoryItems(list);
        mInput->setEditText(currentInputText);
        connect(mInput, SIGNAL(textChanged(const QString&)),
                this, SLOT(textChanged(const QString&)));
    }
    mFromLanguage = newFrom;
    mToLanguage = newTo;
    mContextMenu->clear();
    mContextMenu->insertItem("Translate From", mChooser->getFromMenu());
    mContextMenu->insertItem("Translate To", mChooser->getToMenu());
}

int KLingvoTranslator::languageIndex(const QString &text )
{
    if (checkInput(text) == "Russian")
        return mLanguageList.findIndex(mToLanguage);
    return mLanguageList.findIndex(mFromLanguage);
}

void KLingvoTranslator::popupCombo()
{
    QPoint p;
    if (position() == pRight)
        p = mapToGlobal(QPoint(-mInput->width()-1, 0));
    else
        p = mapToGlobal(QPoint(width()+1, 0));
    mHbox->move(p);
    mHbox->show();
    mInput->setFocus();
}

void KLingvoTranslator::deleteBrowser() {
    delete mBrowser;
    mBrowser = 0;
}

void KLingvoTranslator::showFirstTimeHelp()
{
    KStandardDirs *dirs = KGlobal::dirs();
    QString resourcePath = dirs->findResourceDir("data", "klingvoonline/newintro.html");
    resourcePath += "klingvoonline/";
    QDir resourceDir(resourcePath);
    mTempDir = new KTempDir();
    mTempDir->setAutoDelete(true);
    QStringList files = resourceDir.entryList();
    QStringList urlStrList;
    for (QStringList::Iterator it = files.begin(); it != files.end(); ++it) {
        if ((*it) != "." && (*it) != "..")
            urlStrList.append(resourcePath + (*it));
    }
    KURL::List urlList(urlStrList);
    KURL dest(mTempDir->name());
    KIO::Job *job = KIO::copy(urlList, dest);
    connect(job, SIGNAL(result(KIO::Job*)), this, SLOT(prepareHelpHtml(KIO::Job *)));
}
void KLingvoTranslator::prepareHelpHtml(KIO::Job *job)    
{
    bool error = true;
    if (!job->error()) {
        QFile file(mTempDir->name() + "newintro.html");
        QString text;
        if (file.open(IO_ReadOnly)) {
            QTextStream stream(&file);
            text = stream.read();
            file.close();
            text.replace("#word#", mCurWord);
            text.replace("#selected_url#", mUrl.url());
            if (file.open(IO_WriteOnly)) {
                QTextStream stream(&file);
                stream << text;
                file.close();
                mBrowser->htmlPart()->openURL(KURL(file.name()));
                error = false; // No error if get up to here.
            } 
        }
    }
    if (error)
        mBrowser->openPageForQuery(mUrl.query());        
}

static const char* const KLingvoTranslator_ftable[3][3] = {
    { "void", "translateWordDCOP(QString)", "translateWordDCOP(QString w)" },
    { "void", "translateClipboard()", "translateClipboard()" },
    { 0, 0, 0 }
};
static const int KLingvoTranslator_ftable_hiddens[3] = {
    0,
    0,
    0,
};

bool KLingvoTranslator::process(const QCString &fun, const QByteArray &data, QCString& replyType, QByteArray &replyData)
{
    if ( fun == KLingvoTranslator_ftable[0][1] ) { // void translateWordDCOP(QString)
	QString arg0;
	QDataStream arg( data, IO_ReadOnly );
	if (arg.atEnd()) return false;
	arg >> arg0;
	replyType = KLingvoTranslator_ftable[0][0]; 
	translateWordDCOP(arg0);
    } else if ( fun == KLingvoTranslator_ftable[1][1] ) { // void translateClipboard()
	replyType = KLingvoTranslator_ftable[1][0]; 
	translateClipboard();
    } else{
	return DCOPObject::process( fun, data, replyType, replyData );
    }
    return true;
}

QCStringList KLingvoTranslator::interfaces()
{
    QCStringList ifaces = DCOPObject::interfaces();
    ifaces += "KLingvoTranslator";
    return ifaces;
}

QCStringList KLingvoTranslator::functions()
{
    QCStringList funcs = DCOPObject::functions();
    for ( int i = 0; KLingvoTranslator_ftable[i][2]; i++ ) {
	if (KLingvoTranslator_ftable_hiddens[i])
	    continue;
	QCString func = KLingvoTranslator_ftable[i][0];
	func += ' ';
	func += KLingvoTranslator_ftable[i][2];
	funcs << func;
    }
    return funcs;
}


#include "klingvotranslator.moc"
